package core

import (
	"context"
	"encoding/json"
	"fmt"
	"strings"
	"sync"
	"time"
)

// JobType 表示 Job 类型
type JobType string

const (
	JobTypeSystem  JobType = "system"
	JobTypeLog     JobType = "log"
	JobTypeCommand JobType = "command"
	JobTypeScript  JobType = "script"
)

// JobStatus 表示 Job 执行状态
type JobStatus string

const (
	JobPending   JobStatus = "pending"
	JobRunning   JobStatus = "running"
	JobCompleted JobStatus = "completed"
	JobFailed    JobStatus = "failed"
	JobCancelled JobStatus = "cancelled"
)

// Job 是 Task 的子任务
type Job struct {
	ID         string
	Type       JobType
	Name       string
	Status     JobStatus
	Progress   float64
	Context    context.Context
	CancelFunc context.CancelFunc
	Error      error
	Execute    func(ctx context.Context) error // Job 执行逻辑
	mu         sync.RWMutex
}

type JobView struct {
	ID       string    `json:"id"`
	Type     JobType   `json:"type"`
	Name     string    `json:"name"`
	Status   JobStatus `json:"status"`
	Progress float64   `json:"progress"`
}

// Run 执行 Job
func (j *Job) Run() {
	j.mu.Lock()
	j.Status = JobRunning
	j.mu.Unlock()

	if err := j.Execute(j.Context); err != nil {
		j.mu.Lock()
		select {
		case <-j.Context.Done():
			j.Status = JobCancelled
		default:
			j.Status = JobFailed
			j.Error = err
		}
		j.mu.Unlock()
	} else {
		j.mu.Lock()
		j.Status = JobCompleted
		j.Progress = 100
		j.mu.Unlock()
	}
}

// TaskStatus 表示 Task 执行状态
type TaskStatus string

const (
	TaskPending   TaskStatus = "pending"
	TaskRunning   TaskStatus = "running"
	TaskCompleted TaskStatus = "completed"
	TaskFailed    TaskStatus = "failed"
	TaskCancelled TaskStatus = "cancelled"
)

// Task 表示一次完整的收集任务
type Task struct {
	ID        string
	Name      string
	Jobs      []*Job
	Status    TaskStatus
	Progress  float64
	OutputDir string
	Format    string
	StartTime time.Time
	EndTime   time.Time
	Context   context.Context
	Cancel    context.CancelFunc
	mu        sync.RWMutex
}

type TaskView struct {
	ID        string     `json:"id"`
	Name      string     `json:"name"`
	Status    TaskStatus `json:"status"`
	Progress  float64    `json:"progress"`
	Jobs      []*JobView `json:"jobs"`
	StartTime time.Time  `json:"start_time"`
	EndTime   time.Time  `json:"end_time"`
}

// UpdateProgress 根据 Job 状态更新 Task Progress
func (t *Task) UpdateProgress() {
	t.mu.Lock()
	defer t.mu.Unlock()

	total := len(t.Jobs)
	if total == 0 {
		t.Progress = 100
		t.Status = TaskCompleted
		return
	}

	completed := 0
	for _, j := range t.Jobs {
		if j.Status == JobCompleted {
			completed++
		}
	}

	t.Progress = float64(completed) / float64(total) * 100

	// 更新 Task 状态
	if completed == total {
		t.Status = TaskCompleted
	} else {
		t.Status = TaskRunning
	}
}

// CancelTask 取消 Task 和所有 Job
func (t *Task) CancelTask() {
	t.mu.Lock()
	defer t.mu.Unlock()
	t.Cancel()
	for _, j := range t.Jobs {
		if j.CancelFunc != nil {
			j.CancelFunc()
		}
	}
	t.Status = TaskCancelled
}

// toSerializable 生成可序列化的纯净对象（避免 context / func / cancelFunc 等字段不能 JSON 化）
func (t *Task) toSerializable() *TaskView {
	t.mu.RLock()
	defer t.mu.RUnlock()

	view := TaskView{
		ID:        t.ID,
		Name:      t.Name,
		Status:    t.Status,
		Progress:  t.Progress,
		StartTime: t.StartTime,
		EndTime:   t.EndTime,
	}

	for _, j := range t.Jobs {
		j.mu.RLock()
		view.Jobs = append(view.Jobs, &JobView{
			ID:       j.ID,
			Type:     j.Type,
			Name:     j.Name,
			Status:   j.Status,
			Progress: j.Progress,
		})
		j.mu.RUnlock()
	}
	return &view
}

func (t *Task) Print(isJson bool) (string, error) {
	if isJson {
		data, err := json.Marshal(t.toSerializable())
		if err != nil {
			return "", err
		}
		return string(data), nil
	}
	var b strings.Builder
	b.WriteString(fmt.Sprintf("Task [%s] - %s\n", t.ID, t.Name))
	b.WriteString(fmt.Sprintf("  Status   : %s\n", t.Status))
	b.WriteString(fmt.Sprintf("  Progress : %.2f%%\n", t.Progress))
	b.WriteString(fmt.Sprintf("  Output   : %s\n", t.OutputDir))
	b.WriteString(fmt.Sprintf("  Format   : %s\n", t.Format))
	b.WriteString(fmt.Sprintf("  Start    : %s\n", t.StartTime.Format(time.RFC3339)))
	if !t.EndTime.IsZero() {
		b.WriteString(fmt.Sprintf("  End      : %s\n", t.EndTime.Format(time.RFC3339)))
	}

	b.WriteString("  Jobs:\n")
	for _, job := range t.Jobs {
		b.WriteString(fmt.Sprintf("    - [%s] %s (%s) status=%s progress=%.2f%%",
			job.ID, job.Name, job.Type, job.Status, job.Progress))
		if job.Error != nil {
			b.WriteString(fmt.Sprintf(" error=%v", job.Error))
		}
		b.WriteString("\n")
	}
	return b.String(), nil
}
